<?php

if (! defined ( 'BASEPATH' ))
	exit ( 'No direct script access allowed' );
/**
 * CodeIgniter
 *
 * An open source application development framework for PHP 5.1.6 or newer
 *
 * @package		CodeIgniter
 * @author		EllisLab Dev Team
 * @copyright	Copyright (c) 2006 - 2011, EllisLab, Inc.
 * @license		http://codeigniter.com/user_guide/license.html
 * @link		http://codeigniter.com
 * @since		Version 1.0
 * @filesource
 */

// ------------------------------------------------------------------------


/**
 * CodeIgniter Driver Library Class
 *
 * This class enables you to create "Driver" libraries that add runtime ability
 * to extend the capabilities of a class via additional driver objects
 *
 * @package		CodeIgniter
 * @subpackage	Libraries
 * @category	Libraries
 * @author		EllisLab Dev Team
 * @link
 */
class CI_Driver_Library {
	
	protected $valid_drivers = array ();
	protected static $lib_name;
	
	// The first time a child is used it won't exist, so we instantiate it
	// subsequents calls will go straight to the proper child.
	function __get($child) {
		if (! isset ( $this->lib_name )) {
			$this->lib_name = get_class ( $this );
		}
		
		// The class will be prefixed with the parent lib
		$child_class = $this->lib_name . '_' . $child;
		
		// Remove the CI_ prefix and lowercase
		$lib_name = ucfirst ( strtolower ( str_replace ( 'CI_', '', $this->lib_name ) ) );
		$driver_name = strtolower ( str_replace ( 'CI_', '', $child_class ) );
		
		if (in_array ( $driver_name, array_map ( 'strtolower', $this->valid_drivers ) )) {
			// check and see if the driver is in a separate file
			if (! class_exists ( $child_class )) {
				// check application path first
				foreach ( array (APPPATH, BASEPATH ) as $path ) {
					// loves me some nesting!
					foreach ( array (ucfirst ( $driver_name ), $driver_name ) as $class ) {
						$filepath = $path . 'libraries/' . $lib_name . '/drivers/' . $class . '.php';
						
						if (file_exists ( $filepath )) {
							include_once $filepath;
							break;
						}
					}
				}
				
				// it's a valid driver, but the file simply can't be found
				if (! class_exists ( $child_class )) {
					log_message ( 'error', "Unable to load the requested driver: " . $child_class );
					show_error ( "Unable to load the requested driver: " . $child_class );
				}
			}
			
			$obj = new $child_class ();
			$obj->decorate ( $this );
			$this->$child = $obj;
			return $this->$child;
		}
		
		// The requested driver isn't valid!
		log_message ( 'error', "Invalid driver requested: " . $child_class );
		show_error ( "Invalid driver requested: " . $child_class );
	}

	// --------------------------------------------------------------------


}
// END CI_Driver_Library CLASS


/**
 * CodeIgniter Driver Class
 *
 * This class enables you to create drivers for a Library based on the Driver Library.
 * It handles the drivers' access to the parent library
 *
 * @package		CodeIgniter
 * @subpackage	Libraries
 * @category	Libraries
 * @author		EllisLab Dev Team
 * @link
 */
class CI_Driver {
	protected $parent;
	
	private $methods = array ();
	private $properties = array ();
	
	private static $reflections = array ();
	
	/**
	 * Decorate
	 *
	 * Decorates the child with the parent driver lib's methods and properties
	 *
	 * @param	object
	 * @return	void
	 */
	public function decorate($parent) {
		$this->parent = $parent;
		
		// Lock down attributes to what is defined in the class
		// and speed up references in magic methods
		

		$class_name = get_class ( $parent );
		
		if (! isset ( self::$reflections [$class_name] )) {
			$r = new ReflectionObject ( $parent );
			
			foreach ( $r->getMethods () as $method ) {
				if ($method->isPublic ()) {
					$this->methods [] = $method->getName ();
				}
			}
			
			foreach ( $r->getProperties () as $prop ) {
				if ($prop->isPublic ()) {
					$this->properties [] = $prop->getName ();
				}
			}
			
			self::$reflections [$class_name] = array ($this->methods, $this->properties );
		} else {
			list ( $this->methods, $this->properties ) = self::$reflections [$class_name];
		}
	}
	
	// --------------------------------------------------------------------
	

	/**
	 * __call magic method
	 *
	 * Handles access to the parent driver library's methods
	 *
	 * @access	public
	 * @param	string
	 * @param	array
	 * @return	mixed
	 */
	public function __call($method, $args = array()) {
		if (in_array ( $method, $this->methods )) {
			return call_user_func_array ( array ($this->parent, $method ), $args );
		}
		
		$trace = debug_backtrace ();
		_exception_handler ( E_ERROR, "No such method '{$method}'", $trace [1] ['file'], $trace [1] ['line'] );
		exit ();
	}
	
	// --------------------------------------------------------------------
	

	/**
	 * __get magic method
	 *
	 * Handles reading of the parent driver library's properties
	 *
	 * @param	string
	 * @return	mixed
	 */
	public function __get($var) {
		if (in_array ( $var, $this->properties )) {
			return $this->parent->$var;
		}
	}
	
	// --------------------------------------------------------------------
	

	/**
	 * __set magic method
	 *
	 * Handles writing to the parent driver library's properties
	 *
	 * @param	string
	 * @param	array
	 * @return	mixed
	 */
	public function __set($var, $val) {
		if (in_array ( $var, $this->properties )) {
			$this->parent->$var = $val;
		}
	}

	// --------------------------------------------------------------------


}
// END CI_Driver CLASS

/* End of file Driver.php */
/* Location: ./system/libraries/Driver.php */
